package com.jcx.ldzj.config;

import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy;
import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
import org.apache.shiro.cache.MemoryConstrainedCacheManager;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;

import java.util.HashMap;

@Configuration
public class ShiroConfig {

    @Bean
    @Lazy
    public DefaultWebSecurityManager myDefaultWebSecurityManager(AuthorizingRealm myRealm) {
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();

        //认证策略设定​	AllSuccessfulStrategy 需要所有的Realm认证成功，才能最终认证成功
        //​	AtLeastOneSuccessfulStrategy（默认） 至少有一个认证成功，才能最终认证成功
        //2​	FirstSuccessfulStrategy 第一个Realm认证成功后即返回认证成功，不再进行后面的认证
        //这一段必须在Realm之前，不然Realm没效果
        ModularRealmAuthenticator authenticator = new ModularRealmAuthenticator();
        authenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());
        defaultWebSecurityManager.setAuthenticator(authenticator);


        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        //加密方式，密码加密，加盐，加密次数
        //SimpleHash simpleHash=new SimpleHash("MD5", ByteSource.Util.bytes("密码"),"salt加盐",3);

        matcher.setHashAlgorithmName("MD5");
        matcher.setHashIterations(1);
        myRealm.setCredentialsMatcher(matcher);
        defaultWebSecurityManager.setRealm(myRealm);

        //配置缓存
        MemoryConstrainedCacheManager cacheManager = new MemoryConstrainedCacheManager();
        defaultWebSecurityManager.setCacheManager(cacheManager);
        return defaultWebSecurityManager;
    }

    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager myDefaultWebSecurityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(myDefaultWebSecurityManager);
        //配置路径过滤器
        HashMap<String, String> filterMap = new HashMap<>();
        //key是ant路径，支持**代表多级路径，*代表单级路径，？代表一个字符，value配置的默认过滤器
        //shiro的默认过滤器，可以在org.apache.shiro.web.filter.mgt.DefaultFilter中查看
        //这一段如果不注释，swagger文档都进不去
        //同时这一段也关系到是否走myrealm里面的过滤admin，如果这一段没加上的话，哪怕那些不加注解的接口一样无法调用
        //如果加上这一行  filterMap.put("/*/**","authc");，则必须要一起把不控制的也加上，否则哪怕没加注解的地址也会被拦截
        //但是依然会走MyRealm里面的isPermitted方法校验所以对于登陆后能访问的接口可以不用控制，但若是公用的接口则依然要在这下面标明清楚
        filterMap.put("/system/getVerify", "anon");
        filterMap.put("/system/getEmailCode", "anon");
        filterMap.put("/user-info/updatePassword", "anon");
        filterMap.put("/user-info/login", "anon");
        filterMap.put("/user-info/getUser", "anon");
        filterMap.put("/user-info/updateThis", "anon");
        filterMap.put("/user-info/updatePwdOld", "anon");
        filterMap.put("/sys-menu/getMenuTreeByAuth", "anon");
        filterMap.put("/role-info/list", "anon");
        filterMap.put("/login-system-info/getloginCount", "anon");
        filterMap.put("/dictionaries-type/listDictionaries", "anon");
        filterMap.put("/dictionaries-data/dicdataByType", "anon");
        filterMap.put("/department-info/list", "anon");
        filterMap.put("/*/**", "authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
        shiroFilterFactoryBean.setUnauthorizedUrl("/noauth");
        return shiroFilterFactoryBean;
    }

    /**
     * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions)
     *
     * @return
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }

    /**
     * 开启aop注解支持
     *
     * @param myDefaultWebSecurityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager myDefaultWebSecurityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(myDefaultWebSecurityManager);
        return authorizationAttributeSourceAdvisor;
    }
}
